package com.wongoing.util;

import java.util.Map;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.springframework.web.servlet.ModelAndView;

import com.wongoing.base.BaseSubjectModel;
import com.wongoing.sys.shiro.ShiroUser;
import com.wongoing.sys.util.Constants;
import com.wongoing.sys.viewmodel.JsonResult;

public class SubjectUtil {
	
	public static final String SHIRO_USER = "shiroUser";
	public static final String SHIRO_CUSTOMER= "shiroCustomer";
	public static final String SHIRO_MERCHANT= "shiroMerchant";
	
	/**
	 * 功能说明：用户账户控制
	 * 修改说明：
	 * @author 吴兆强
	 * @date 2017年11月25日 上午8:59:19
	 * @param clazz
	 * @param loginType
	 * @param log
	 * @return
	 * @throws Exception
	 */
	public static BaseSubjectModel validate(ModelAndView mv, Class clazz,LoginType loginType,String log) throws Exception{
		
		boolean flag = false;
		ShiroUser shiroUser = null;
		log = log == null ? "" : log;
		
		//登录账户验证部分
		// 验证当前是否为登录账号，未登录则跳转登录页面,状态码：14。注：先注销，再直接登录
		Subject subject = SecurityUtils.getSubject();
		if (!subject.isAuthenticated()) {
			mv = new ModelAndView();
			mv.addObject("errorMap", Status.SIGN_NO.toString());
			mv.addObject("loginTypeName", loginType.getTypeZh());
			mv.addObject("loginUrl", loginType.getTypeUrl());
			mv.setViewName(ModelAndViewConstants.PASS_FAIL);
			LogService.getInstance(clazz).debug(log+Status.SIGN_NO.toString());
			return setBaseSubjectModel(flag,shiroUser,mv,subject);
		}
		
		//当前登录用户信息获取，获取未null则返回失败信息，状态码：13。注：先注销，再登录
		shiroUser = (ShiroUser) subject.getSession().getAttribute(SubjectUtil.SHIRO_USER);
		if (shiroUser == null) {
			mv = new ModelAndView();
			mv.addObject("errorMap", Status.SIGN_IN_ABNORMAL.toString());
			mv.addObject("loginTypeName", loginType.getTypeZh());
			mv.addObject("loginUrl", loginType.getTypeUrl());
			mv.setViewName(ModelAndViewConstants.PASS_FAIL);
			LogService.getInstance(clazz).debug(log+Constants.SIGN_IN_ABNORMAL.toString());
			return setBaseSubjectModel(flag,shiroUser,mv,subject);
		}
		
		// 检测为哪个系统登录，如果为商家版则继续执行下一步，否则返回错误信息，状态码：19.注：先注销再登录
		if (!loginType.getTypeEn().equals(shiroUser.getUserType())) {
			String tmp = "您处于" + getCurrentUserZhDes(subject) + "登录状态，请登录"+loginType.getTypeZh()+"系统进行操作（注：新系统登陆后，原系统将被注销）！";
			mv = new ModelAndView();
			mv.addObject("errorMap", tmp);
			mv.addObject("loginTypeName", loginType.getTypeZh());
			mv.addObject("loginUrl", loginType.getTypeUrl());
			mv.setViewName(ModelAndViewConstants.PASS_FAIL);
			LogService.getInstance(clazz).debug(log+tmp);
			return setBaseSubjectModel(flag,shiroUser,mv,subject);
		}
		
		flag = true;
		return setBaseSubjectModel(flag,shiroUser,mv,subject);
	}
	
	/**
	 * 功能说明：用户状态控制
	 * 修改说明：
	 * @author 吴兆强
	 * @date 2017年11月24日 上午11:01:16
	 * @param clazz 当前class，用来输出日志使用
	 * @param loginType 登录类型（后台、前台、商家等）
	 * @param log log的错误前缀，用于错误描述
	 * @return 返回json
	 * @throws Exception
	 */
	public static BaseSubjectModel validate(Class clazz,LoginType loginType,String log) throws Exception{
		
		Map<String, Object> jsonResult = null;
		boolean flag = false;
		ShiroUser shiroUser = null;
		log = log == null ? "" : log;
		
		//登录账户验证部分
		// 验证当前是否为登录账号，未登录则跳转登录页面,状态码：14。注：先注销，再直接登录
		Subject subject = SecurityUtils.getSubject();
		if (!subject.isAuthenticated()) {
			jsonResult = JsonResult.jsonWsReturn(Status.ERROR.getCode(), Status.SIGN_NO.toString(), Status.SIGN_NO.getCode());
			LogService.getInstance(clazz).debug(log+Constants.SIGN_NO.toString());
			return setBaseSubjectModel(flag,shiroUser,jsonResult,subject);
		}
		
		//当前登录用户信息获取，获取未null则返回失败信息，状态码：13。注：先注销，再登录
		shiroUser = (ShiroUser) subject.getSession().getAttribute(SubjectUtil.SHIRO_USER);
		if (shiroUser == null) {
			jsonResult = JsonResult.jsonWsReturn(Status.ERROR.getCode(), Status.SIGN_IN_ABNORMAL.toString(), Status.SIGN_IN_ABNORMAL.getCode());
			LogService.getInstance(clazz).debug(log+Constants.SIGN_IN_ABNORMAL.toString());
			return setBaseSubjectModel(flag,shiroUser,jsonResult,subject);
		}
		
		// 检测为哪个系统登录，如果为商家版则继续执行下一步，否则返回错误信息，状态码：19.注：先注销再登录
		if (!loginType.getTypeEn().equals(shiroUser.getUserType())) {
			String tmp = "您处于" + getCurrentUserZhDes(subject) + "登录状态登录状态，请登录"+loginType.getTypeZh()+"系统进行操作（注：新系统登陆后，原系统将被注销）！";
			jsonResult = JsonResult.jsonWsReturn(Status.ERROR.getCode(), tmp, Status.OTHER_SYSTEM_IS_LOGIN.getCode());
			LogService.getInstance(clazz).debug(log+tmp);
			return setBaseSubjectModel(flag,shiroUser,jsonResult,subject);
		}
		
		flag = true;
		return setBaseSubjectModel(flag,shiroUser,jsonResult,subject);
	}
	
	/**
	 * 功能说明：设置返回参数 - Json Result 
	 * 修改说明：
	 * @author 吴兆强
	 * @date 2017年11月24日 上午11:07:44
	 * @param flag 验证是否成功的标识，true表示验证通过，false失败
	 * @param shiroUser 用户登录信息实体
	 * @param jsonResult 返回json数据
	 * @return
	 */
	private static BaseSubjectModel setBaseSubjectModel(boolean flag,ShiroUser shiroUser,Map<String,Object> jsonResult,Subject subject) {
		BaseSubjectModel bsm = new BaseSubjectModel();
		bsm.setFlag(flag);
		bsm.setShiroUser(shiroUser);
		bsm.setJsonResult(jsonResult);
		bsm.setSubject(subject);
		return bsm;
	}
	
	/**
	 * 功能说明：设置返回参数-ModelAndView
	 * 修改说明：
	 * @author 吴兆强
	 * @date 2017年11月25日 上午9:46:54
	 * @param flag 验证是否成功的标识，true表示验证通过，false失败
	 * @param shiroUser 用户登录信息实体
	 * @param mv 返回ModelAndView数据
	 * @return
	 */
	private static BaseSubjectModel setBaseSubjectModel(boolean flag,ShiroUser shiroUser,ModelAndView mv,Subject subject) {
		BaseSubjectModel bsm = new BaseSubjectModel();
		bsm.setFlag(flag);
		bsm.setShiroUser(shiroUser);
		bsm.setMv(mv);
		bsm.setSubject(subject);
		return bsm;
	}
	
	/**
	 * 功能说明：获取登录状态
	 * 修改说明：shiro验证共用一个util，所以只要一个系统登录成功则该函数返回true,
	 * 为实现唯一系统的登录，需要获取登录用户实体类ShiroUser，使用其中的userType对
	 * 用户类型进行区分。
	 * @author 吴兆强
	 * @date 2017年11月13日 下午4:42:12
	 * @return
	 */
	public static boolean isLogin() {
		return SecurityUtils.getSubject().isAuthenticated();
	}
	
	/**
	 * 
	 * 功能说明：获取当前登录用户实体类
	 * 修改说明：
	 * @author 吴兆强
	 * @date 2017年11月13日 下午4:37:27
	 * @return ShiroUser 登录用户的实体类
	 */
	public static ShiroUser getCurrentUser() {
		ShiroUser s = new ShiroUser(0, "guest",LoginType.GUEST.getTypeEn());
		try {
			Subject subject = SecurityUtils.getSubject();
			s = (ShiroUser) subject.getSession().getAttribute(SHIRO_USER);
		} catch (Exception e) {
			s = new ShiroUser(-1, "abnormal",LoginType.ABNORMAL.getTypeEn());
		}
		return s;
	}
	
	/**
	 * 
	 * 功能说明：获取当前登录用户实体类
	 * 修改说明：
	 * @author 吴兆强
	 * @date 2017年11月13日 下午4:37:27
	 * @return ShiroUser 登录用户的实体类
	 */
	public static ShiroUser getCurrentUser(Subject subject) {
		ShiroUser s = new ShiroUser(0, "guest",LoginType.GUEST.getTypeEn());
		try {
			s = (ShiroUser) subject.getSession().getAttribute(SHIRO_USER);
		} catch (Exception e) {
			s = new ShiroUser(-1, "abnormal",LoginType.ABNORMAL.getTypeEn());
		}
		return s;
	}
	/**
	 * 功能说明：获取当前用户为何种用户的中文描述
	 * 修改说明：
	 * @author 吴兆强
	 * @date 2017年11月13日 下午5:26:52
	 * @return
	 */
	public static String getCurrentUserZhDes() {
		//默认返回后台用户
		String result = LoginType.USER.getTypeZh();
		ShiroUser u = getCurrentUser();
		if(LoginType.GUEST.getTypeEn().equals(u.getUserType())) {
			//游客登录
			result = LoginType.GUEST.getTypeZh();
		}else if(LoginType.ABNORMAL.getTypeEn().equals(u.getUserType())) {
			//异常用户
			result = LoginType.ABNORMAL.getTypeZh();
		}else if(LoginType.CUSTOMER.getTypeEn().equals(u.getUserType())) {
			//客户用户
			result = LoginType.CUSTOMER.getTypeZh();
		}else if(LoginType.MERCHANT.getTypeEn().equals(u.getUserType())) {
			//商家用户	
			result = LoginType.MERCHANT.getTypeZh();
		}
		return result;
	}
	/**
	 * 功能说明：获取当前用户为何种用户的中文描述
	 * 修改说明：
	 * @author 吴兆强
	 * @date 2017年11月13日 下午5:26:52
	 * @return
	 */
	public static String getCurrentUserZhDes(Subject subject) {
		//默认返回后台用户
		String result = LoginType.USER.getTypeZh();
		ShiroUser u = getCurrentUser(subject);
		if(LoginType.GUEST.getTypeEn().equals(u.getUserType())) {
			//游客登录
			result = LoginType.GUEST.getTypeZh();
		}else if(LoginType.ABNORMAL.getTypeEn().equals(u.getUserType())) {
			//异常用户
			result = LoginType.ABNORMAL.getTypeZh();
		}else if(LoginType.CUSTOMER.getTypeEn().equals(u.getUserType())) {
			//客户用户
			result = LoginType.CUSTOMER.getTypeZh();
		}else if(LoginType.MERCHANT.getTypeEn().equals(u.getUserType())) {
			//商家用户	
			result = LoginType.MERCHANT.getTypeZh();
		}
		return result;
	}
}
